package com.tangcco.lockwell.configuration.spring.security;

import com.tangcco.lockwell.configuration.property.CookieConfig;
import com.tangcco.lockwell.domain.RegisterPhoneValidateCode;
import com.tangcco.lockwell.domain.User;
import com.tangcco.lockwell.domain.enums.RoleEnum;
import com.tangcco.lockwell.service.RegisterPhoneValidateService;
import com.tangcco.lockwell.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;

/**
 * 手机号和验证码登录过滤器
 */
public class RestPhoneCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private static final Logger logger = LoggerFactory.getLogger(RestPhoneCodeAuthenticationFilter.class);
    private final RegisterPhoneValidateService registerPhoneValidateService;
    private final UserService userService;
    public RestPhoneCodeAuthenticationFilter(RegisterPhoneValidateService registerPhoneValidateService, UserService userService) {
        super(new AntPathRequestMatcher("/api/student/user/loginByPhoneCode", "POST"));
        this.registerPhoneValidateService = registerPhoneValidateService;
        this.userService = userService;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {
        request.setAttribute(TokenBasedRememberMeServices.DEFAULT_PARAMETER, false);
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String phone = request.getParameter("phone");
        String code = request.getParameter("validCode");

        if (phone == null || phone.trim().isEmpty()) {
            throw new AuthenticationServiceException("手机号不能为空");
        }
        if (code == null || code.trim().isEmpty()) {
            throw new AuthenticationServiceException("验证码不能为空");
        }

        // 验证手机号是否合法
        if (!isValidPhoneNumber(phone)) {
            throw new AuthenticationServiceException("手机号格式不正确");
        }
        // 校验验证码
        RegisterPhoneValidateCode validateCode = registerPhoneValidateService.selectByPhoneAndSendType(phone, 3);
        if (validateCode == null) {
            throw new AuthenticationServiceException("验证码不存在");
        }
        if (!validateCode.getValidCode().equals(code)) {
            throw new AuthenticationServiceException("验证码错误");
        }
        // 给定的时间
        LocalDateTime givenTime = convertToLocalDateTime(validateCode.getCreateTime());
        // 当前时间
        LocalDateTime currentTime = LocalDateTime.now();
        if (!isWithinOneMinute(givenTime, currentTime)) {
            throw new AuthenticationServiceException("验证码已过期");
        }
        // 根据手机号获取用户信息
        User user = userService.getUserByPhone(phone);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        // 验证成功，返回身份认证结果
        ArrayList<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        grantedAuthorities.add(new SimpleGrantedAuthority(RoleEnum.fromCode(user.getRole()).getRoleName()));

        org.springframework.security.core.userdetails.User authUser = new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), grantedAuthorities);
        return new UsernamePasswordAuthenticationToken(authUser, authUser.getPassword(), authUser.getAuthorities());
    }

    private void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }
    // 验证手机号是否合法
    private boolean isValidPhoneNumber(String phoneNumber) {
        // 定义手机号的正则表达式模式
        String regex = "^1[3-9]\\d{9}$";
        return phoneNumber.matches(regex);
    }

    public static boolean isWithinOneMinute(LocalDateTime time1, LocalDateTime time2) {
        Duration duration = Duration.between(time1, time2).abs();
        return duration.getSeconds() <= 60;
    }

    public static LocalDateTime convertToLocalDateTime(Date date) {
        // 获取 Date 对象的时间戳
        Instant instant = date.toInstant();
        // 使用系统默认的时区将 Instant 转换为 LocalDateTime
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    /**
     * Sets user details service.
     *
     * @param userDetailsService the user details service
     */
    void setUserDetailsService(UserDetailsService userDetailsService) {
        RestTokenBasedRememberMeServices tokenBasedRememberMeServices = new RestTokenBasedRememberMeServices(CookieConfig.getName(), userDetailsService);
        tokenBasedRememberMeServices.setTokenValiditySeconds(CookieConfig.getInterval());
        setRememberMeServices(tokenBasedRememberMeServices);
    }
}